<template>
	<div class="it-road-container">
		<div id="itRoadContainerSec" style="position: relative"></div>
		<div id="miniMapId"></div>
		<div v-if="config.noDataFlag" class="no-data">暂无数据</div>
	</div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted, nextTick, onBeforeMount } from 'vue';
import G6 from '@antv/g6';
import { G6GraphEvent } from '@antv/g6';
import registerLayout from './layout';
import registerShape from './shape';
import registerBehavior from './behavior';

import { ConfigType, GraphCustomOptionsType, GraphData } from './itRoad-type';
const props = defineProps<{
	config: ConfigType;
}>();

const $emit = defineEmits(['dragNode', 'afterRender', 'clickNode', 'dblclickNode', 'graphInited']);

// g6 graph对象
const graph = ref();
// 防抖
const debounce = reactive({
	// 频率(ms)
	time: 100,
	flag: true,
});
const clicktime = ref();
// 缩略图插件
const minimap = ref(null);
// IT路径图数据
const itRoadData: GraphData = reactive({
	nodes: [],
	edges: [],
});

const nodeType = computed(() => {
	return props.config.type;
});
// console.log('nodetype.value', nodeType.value);
onBeforeMount(async () => {
	// 加载自定义 布局、样式和文本、交互行为配置
	Promise.all([registerLayout(G6, nodeType.value), registerShape(G6, nodeType.value), registerBehavior(G6, nodeType.value)])
		.then((res) => {
			$emit('graphInited');
			console.log('graph初始化完成--------------,', res);
		})
		.catch((e) => {
			console.log('e', e);
		});
});

onMounted(() => {
	// console.log('props.config.type', props.config.type);
	// // 加载配置
	// registerLayout(G6, props.config.type);
	// registerShape(G6, props.config.type);
	// registerBehavior(G6, props.config.type);

	nextTick(() => {
		// 初始化
		initGraph();
	});
});
// 初始化
function initGraph() {
	// 获取画布长宽
	let width = props.config.canvasWidth,
		height = props.config.canvasHeight;
	if (!width) {
		width = document.getElementById('itRoadContainerSec')!.scrollWidth - 1;
	}
	if (!height) {
		height = (document.documentElement.clientHeight || document.body.clientHeight) - 160;
	}

	// 默认配置
	let defaultOptions = reactive<GraphCustomOptionsType>({
		// 最小缩放比例
		minZoom: 0.5,
		// 最大缩放比例
		maxZoom: 2,
		// 布局配置项
		layout: {
			type: 'dagre',
			rankdir: 'LR',
			nodesep: 50,
			ranksep: 100,
		},
		modes: {
			// 默认模式
			defaultMode: [
				// 拖拽画布
				'drag-canvas',
				// 缩放画布
				'zoom-canvas',
				// 节点高亮(自定义)
				'activate-node',
			],
			edit: [
				// 拖拽画布
				'drag-canvas',
				// 缩放画布
				'zoom-canvas',
				// 拖拽节点
				'drag-node',
				// 节点高亮(自定义)
				'activate-node',
			],
			editNoDragNode: [
				// 拖拽画布
				'drag-canvas',
				// 缩放画布
				'zoom-canvas',
				// 节点高亮(自定义)
				'activate-node',
			],
		},
	});
	// 合并自定义配置项
	if (props.config.customOptions) {
		defaultOptions = { ...defaultOptions, ...props.config.customOptions };
	}
	console.log('itRoadContainerSec', height);

	const graphObj = new G6.Graph({
		// 图的  DOM 容器，可以传入该 DOM 的 id 或者直接传入容器的 HTML 节点对象
		container: 'itRoadContainerSec',
		// 指定画布宽度，单位为 'px'
		width: width,
		// 指定画布高度，单位为 'px'
		height: height,
		// 是否开启画布自适应。开启后图自动适配画布大小
		fitView: true,
		// v3.5.1 后支持。开启后，图将会被平移，图的中心将对齐到画布中心，但不缩放。优先级低于 fitView
		fitCenter: true,
		// 最小缩放比例
		minZoom: defaultOptions.minZoom,
		// 最大缩放比例
		maxZoom: defaultOptions.maxZoom,
		// 渲染方式，该配置项除 V3.3.x 外其他版本均支持 'canvas' / 'svg'
		renderer: defaultOptions.renderer || 'canvas',
		// 是否启用 stack，即是否开启 redo & undo 功能，该配置项 V3.6 及以上版本支持
		// enabledStack: false,
		// 插件
		plugins: [],
		// 设置画布的模式
		modes: {
			// 默认模式
			default: defaultOptions.modes?.defaultMode,
			// 编辑模式
			edit: defaultOptions.modes?.edit,
			// 编辑模式-不拖动节点
			editNoDragNode: defaultOptions.modes?.editNoDragNode,
		},
		// 布局配置项，使用 type 字段指定使用的布局方式，type 可取以下值：random, radial, mds, circular, fruchterman, force, dagre，各布局详细的配置请参考
		layout: defaultOptions.layout,
		/* layout: {
              type: 'allItRoadLayout'
            }, */
		// 默认状态下节点的配置，比如 type, size, color。会被写入的 data 覆盖
		defaultNode: {
			type: nodeType.value,
		},
		// 默认状态下边的配置，比如 type, size, color。会被写入的 data 覆盖
		defaultEdge: {
			type: 'myCubicHorizontal',
			labelCfg: {
				refY: 10,
				style: {
					fill: '#2beded',
				},
			},
		},
		// 各个状态下节点的样式，例如 hover、selected，3.1 版本新增
		nodeStateStyles: {},
		// 各个状态下边的样式，例如 hover、selected，3.1 版本新增
		edgeStateStyles: {},
	});
	graph.value = graphObj;

	// 默认加载的插件
	// toggleShowMinimap();

	if (defaultOptions.toolbarObj) {
		const toolbar = new G6.ToolBar(defaultOptions.toolbarObj);
		graph.value.addPlugin(toolbar);
	}

	// 绑定事件
	// 1、拖拽
	graph.value.on('dragend', (ev: G6GraphEvent) => {
		// 防抖
		if (!checkDebounce()) {
			return;
		}
		if (!ev.item) {
			return;
		}
		$emit('dragNode', ev);
	});

	// 2、双击
	graph.value.on('dblclick', (ev: G6GraphEvent) => {
		clearTimeout(clicktime.value);
		// 防抖
		if (!checkDebounce()) {
			return;
		}
		if (!ev.item) {
			return;
		}
		$emit('dblclickNode', ev);
	});

	// 3、单击
	graph.value.on('click', (ev: G6GraphEvent) => {
		clearTimeout(clicktime.value);

		clicktime.value = setTimeout(() => {
			// 防抖
			if (!checkDebounce()) {
				return;
			}
			if (!ev.item) {
				return;
			}

			$emit('clickNode', ev);
		}, 300);
	});

	// 4、页面渲染完成
	graph.value.on('afterrender', () => {
		$emit('afterRender');
	});
}
// 加载IT路径图
function loadItRoadData(data: GraphData) {
	itRoadData.nodes = data.nodes;
	itRoadData.edges = data.edges;
	graph.value.read(itRoadData);
}
// // 切换显示/隐藏缩略图
// function toggleShowMinimap() {
// 	if (minimap.value) {
// 		graph.value.removePlugin(minimap.value);
// 		minimap.value = null;
// 	} else {
// 		// 缩略图
// 		minimap.value = new G6.Minimap({
// 			container: document.getElementById('miniMapId'),
// 			size: [150, 100],
// 		});
// 		graph.addPlugin(minimap.value);
// 	}
// }
// 设置画布模式
function setGraphMode(mode: any) {
	graph.value.setMode(mode);
}
// 设置布局
function setLayout(layout: any) {
	graph.value.updateLayout(layout);
}
// 设置节点状态
function setItemStateById(id: any, stateName: any, flags: boolean) {
	graph.value.setItemState(graph.value.findById(id), stateName, flags);
}
// 更新信息
function updateInfo(data: any) {
	const nodeMap: Record<string, any> = {};
	data.forEach((d: Record<string, any>) => {
		nodeMap[d.mapKey] = d;
	});
	const nodes = graph.value.getNodes();
	nodes.forEach((node: any) => {
		const nodeModel = JSON.parse(JSON.stringify(node.getModel()));
		const dbNode = nodeMap[nodeModel.id];
		if (dbNode && dbNode.status !== '1') {
			nodeModel.status = dbNode.status;
			nodeModel.text.reqCount = dbNode.reqCount + '';
			nodeModel.text.avgDealTime = dbNode.avgDealTime;
			nodeModel.text.health = dbNode.health;
			node.update(nodeModel);
		} else if (nodeModel.status === '1') {
			// 无数据，但不需要更新节点
		} else {
			// 无数据，要更新节点
			nodeModel.status = '1';
			nodeModel.text.reqCount = '0';
			nodeModel.text.avgDealTime = '-';
			nodeModel.text.health = '-';
			node.update(nodeModel);
		}
	});
}
// ture: 通过防抖检查
function checkDebounce() {
	if (debounce.flag) {
		debounce.flag = false;
		setTimeout(function () {
			debounce.flag = true;
		}, debounce.time);
		return true;
	}
	return false;
}
// 获取所有节点
function getAllNodes() {
	return graph.value.getNodes();
}

// 导出方法让父组件调用
defineExpose({
	setGraphMode,
	setLayout,
	setItemStateById,
	loadItRoadData,
	getAllNodes,
	updateInfo,
	graph: graph,
});
</script>
<style scoped>
:deep(.svg-icon) {
	width: 1.5em;
	height: 1.5em;
}
</style>
<style rel="stylesheet/scss" lang="scss">
#miniMapId {
	position: absolute;
	width: 150px;
	height: 100px;
	top: 0;
}

.no-data {
	position: absolute;
	left: 49%;
	top: 49%;
	color: #ffffff70;
}

.it-road-container {
	.g6-component-toolbar {
		left: unset;
		right: 0;
		padding: 0;
		background-color: #ffffff00;
		border: 0;
		color: #ffffff;
		li {
			position: static;
		}
		i {
			font-size: 16px;
		}
	}
}
</style>
